﻿using CleanArchitecture.Core.Configuration;
using CleanArchitecture.Core.Events;
using CleanArchitecture.Core.Helper;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Infrastructure.Entities;
using CleanArchitecture.Infrastructure.Entities.AdminUsers;
using CleanArchitecture.Infrastructure.Entities.Customers;
using CleanArchitecture.Infrastructure.Entities.Settings;
using CleanArchitecture.Infrastructure.Interfaces.AdminUsers;
using CleanArchitecture.Infrastructure.Interfaces.Customers;
using CleanArchitecture.Infrastructure.Interfaces.Security;
using System;

namespace CleanArchitecture.Infrastructure.Services.Customers
{
    public partial class CustomerRegistrationService : ICustomerRegistrationService
    {
        #region Fields
        private readonly ICustomerService _customerService;
        private readonly SecuritySettings _securitySettings;
        private readonly CustomerSettings _customerSettings;
        private readonly IEncryptionService _encryptionService;
        private readonly IWebHelper _webHelper;
        private readonly IDomainEventDispatcher _eventDispatcher;
        #endregion

        #region Ctor
        public CustomerRegistrationService(SecuritySettings securitySettings,
            CustomerSettings customerSettings,
            ICustomerService customerService,
            IEncryptionService encryptionService,
            IWebHelper webHelper,
            IDomainEventDispatcher eventDispatcher)
        {
            this._securitySettings = securitySettings;
            this._customerSettings = customerSettings;
            this._customerService = customerService;
            this._encryptionService = encryptionService;
            this._webHelper = webHelper;
            this._eventDispatcher = eventDispatcher;
        }
        #endregion

        #region Utilities

        /// <summary>
        /// Check whether the entered password matches with a saved one
        /// </summary>
        /// <param name="DbPassword">Customer password</param>
        /// <param name="enteredPassword">The entered password</param>
        /// <returns>True if passwords match; otherwise false</returns>
        protected bool PasswordsMatch(Customer customer, string enteredPassword)
        {
            if(customer == null || string.IsNullOrEmpty(enteredPassword))
                return false;
            if (string.IsNullOrEmpty(customer.Password))
                return false;

            var savedPassword = string.Empty;
            switch (customer.PasswordFormat)
            {
                case EntityEnumConfig.PasswordFormat.Clear:
                    savedPassword = enteredPassword;
                    break;
                case EntityEnumConfig.PasswordFormat.Encrypted:
                    savedPassword = _encryptionService.EncryptText(enteredPassword);
                    break;
                case EntityEnumConfig.PasswordFormat.Hashed:
                    savedPassword = _encryptionService.CreatePasswordHash(enteredPassword, customer.PasswordSalt, _customerSettings.HashedPasswordFormat);
                    break;
                default: //None
                    savedPassword = enteredPassword;
                    break;
            }

            return customer.Password.Equals(savedPassword);
        }

        #endregion

        #region Methods
        /// <summary>
        /// Validate AdminUser
        /// </summary>
        /// <param name="username">Username / email / Mobile</param>
        /// <param name="password">Password</param>
        /// <returns>Result</returns>
        public Customer ValidateCustomer(string username, string password, string verifytype = "passwordandcaptcha")
        {
            Customer user = null;
            bool isLoginname = false;
            if (_securitySettings.CustomerLogin != null && _securitySettings.CustomerLogin?.Count > 0)
            {
                if (_securitySettings.CustomerLogin.Contains(CustomerLoginType.Email.ToString("F")) && CommonHelper.IsValidEmail(username))
                    user = _customerService.GetCustomerByEmail(username);
                else if (_securitySettings.AdminUserLogin.Contains(AdminUserLoginType.Mobile.ToString("F")) && CommonHelper.IsValidMobile(username))
                    user = _customerService.GetCustomerByMobile(username);
                else isLoginname = true;
            }
            else isLoginname = true;
            //else //默认方式（登录用户名）登录
            if(isLoginname) 
                user = _customerService.GetCustomerByLoginname(username);

            if (user == null)
            {
                user = new Customer()
                {
                    ExtraInfo = LoginResults.UserNotExist
                };
                return user;
            }
            if (user.IsDeleted == EntityEnumConfig.DeleteState.Deleted)
            {
                user.ExtraInfo = LoginResults.Deleted;
                return user;
            }
            if (user.IsActive == EntityEnumConfig.LockState.InActive)
            {
                user.ExtraInfo = LoginResults.NotActive;
                return user;
            }

            if (verifytype == "passwordandcaptcha")
            {
                if (!PasswordsMatch(user, password))
                {
                    //wrong password
                    user.FailedLoginAttempts++;
                    int allowedAttemps = _customerSettings.FailedPasswordAllowedAttempts > 0
                                       ? _customerSettings.FailedPasswordAllowedAttempts
                                       : 3;
                    if (user.FailedLoginAttempts >= allowedAttemps)
                    {
                        //lock out
                        user.IsActive = EntityEnumConfig.LockState.InActive;
                        //reset the counter
                        user.FailedLoginAttempts = 0;
                        user.SysLogLvl = SystemLogLevel.Information;
                        user.SysLogMsg = string.Format("前端注册用户：Id: {0}, 登录名: {1}, 输入密码错误次数超过系统设定尝试次数{2}次，已被锁定。",
                                                    user.Id, username, allowedAttemps);
                    }
                    _customerService.UpdateCustomer(user);
                    user.ExtraInfo = LoginResults.WrongPassword;

                    return user;
                }
            }
            else if (verifytype == "smscode")
            {
                //验证短信
                throw new NotImplementedException("短信验证码功能还未接入");
            }
            else throw new NotImplementedException("Unknow customer login type");
            
            //update login details
            user.FailedLoginAttempts = 0;
            user.LastLoginTimeUtc = DateTime.UtcNow;
            user.LastLoginIp = _webHelper.GetCurrentIpAddress();
            user.ExtraInfo = LoginResults.Successful;
            _customerService.UpdateCustomer(user);

            return user;
        }
        #endregion
    }
}
